
#include <string.h>
#include "util.h"
#include "Des.h"
#include "BitDefine.h"
#include "ISO14443Command.h"
#include "CardCommandDefine.h"
#include "CardCommand.h"
//PICC
#include "CardPort.h"
#include "CardPrivate.h"
#include "ISO14443p3a.h"
#include "CardMem.h"
//ICC
#include "Slot.h"
#include "Driver.h"
#include "Bsp.h"

#include "Reader.h"

#include "Env.h"

#include "Debug.h"

#define CardStd_Mask(std)	(0x01 << (std))
#define CardStd_Check(map, std)		(((map) & CardStd_Mask(std)) != 0)

#define CardType_IsMifare(sak)		((sak & 0x08) != 0)
#define CardType_IsCpu(sak)			((sak & 0x20) != 0)

static uint8_t cfgKey[16] =
{
	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
};

static int Reader_CPU_ExternAuth(uint8_t kid, uint8_t key[], uint8_t klen);


static int Reader_SearchTypeA(void* resp, int timeout){
	int ret = Port_Picc_Activate(Card_T_CpuA, PICC_Op_Activate, (ISO14443AInfo_T*)resp);
	if(!ret){
		return ret;
	}
	if(ret == CmdS_NotCompliant){
		return 0;
	}
	return -1;
}

int Reader_DetectTypeA(int timeout){
	ISO14443AInfo_T a;
	return Reader_SearchTypeA(&a, 100) == 0;
}

static inline uint8_t Reader_MultTypeSelect(uint8_t sak)
{
	uint8_t s = sak & 0x28;

	//0x08就是Mifare卡， 0x20是CPU卡
	if (s == 0x28){
		return (envData.rdMifareFirst != 0) ? 0x08: 0x20;
	}
	return sak;
}

static inline int Reader_CheckCustomerCode(uint8_t code[4]){
	return memcmp(envData.Customer_Code, code, 4) == 0;
}

void Reader_MF_GetKey(uint8_t uid[4], uint8_t key[6]){
/*
如卡片的正向UID是5D 54 F9 89则密钥是 75 53 E0 33 AB A2

密钥前三个字节生成的方式：正向UID的从第2―21位（从0开始算）得到20位，再后补4个0凑成24位是密钥前三个字节；
密钥第四个字节生成方式：正向UID全部相加的和值取低8位生成一个字节是密钥的第四个字节；（5D+54+F9+89）
密钥的后二字节生成的方式：UID反向（按字节倒序）后取最后两个字节再全部按位取反得到二个字节是密钥的后两个字节
*/
	uint32_t u = 0;
	Mem_Reverse_Copy((uint8_t *) &u, uid, 3);
	u >>= 2;
	u <<= 4;
	Mem_Reverse_Copy((uint8_t *) key, (uint8_t *)&u, 3);

	uint8_t sum = 0;

	for(int i = 0; i < 4; i++){
		sum += uid[i];
	}
	key[3] = sum;
	
	key[4] = ~uid[1];
	key[5] = ~uid[0];
}


static int Reader_MF_GetLogicSN(ISO14443AInfo_T *a, CSN_T* csn){
	uint8_t blockN = envData.rdMfBlock;
	//读逻辑卡号
	int ret = Port_Picc_Mem_Setup(Card_T_Mifare, a);
	//认证密钥
	MifareAuthParam_T mp = {blockN/4, 0 };
//		uint8_t key[6];
//		Reader_MF_GetKey(a->uid, key);
	ret = Port_Picc_Mem_Authen(&mp, envData.rdMfKey, 6);
	if(ret){
//			memcpy(csn->num, a->uid, 3);
//			csn->nlen = 3;
//			memcpy(csn->ibuf, a->uid, 3);
//			csn->ilen = 3;
//			csn->info = 1;
//			csn->std = Card_T_CpuA;
		return -100;
	}
	//读卡
	uint8_t buf[16];
	ret = Port_Picc_Mem_Read(blockN, buf, 16);
	if(ret){
		return ret;
	}
	//检查客户编码
#if 1
	if(Flag_IsSet(envData.Options_select, ENV_Custom_CheckCode)){
		if(envData.Customer_M1_Position < 12 
		&& !Reader_CheckCustomerCode(buf + envData.Customer_M1_Position)){
			return -1;
		}
	}
	//拷贝卡号
	uint8_t copyLen = envData.ContentLength;
	if(copyLen > 8){
		copyLen = 8;
	}
	if(envData.ContentStartPosition + copyLen > 16 ){
		memcpy(csn->num, buf, copyLen);
		csn->nlen = copyLen;
	}
	else{
		memcpy(csn->num, buf + envData.ContentStartPosition, copyLen);
		csn->nlen = copyLen;
	}
#endif 
//		memcpy(csn->num, buf, 4);
//		csn->nlen = 4;
	csn->std = Card_T_CpuA;
    return ret;
}

static int Reader_MF_GetUID(ISO14443AInfo_T *a, CSN_T* csn){
	int ret = 0;
	
	if(Flag_IsSet(envData.Options_select, ENV_Custom_MF_CheckKey)){
		//需要验证密钥
		ret = Port_Picc_Mem_Setup(Card_T_Mifare, a);
		MifareAuthParam_T mp = {envData.rdMfBlock/4, 0 };
		ret = Port_Picc_Mem_Authen(&mp, envData.rdMfKey, 6);
		if(ret){
			return -100;
		}
		//密钥验证成功，输出UID
	}
	
#if 0
	uint8_t pos;
	uint8_t len;
	
	if(a->ulen != 4){
		pos = envData.Snr8_StartPos;
		len = envData.Snr8_Len;
	}
	else{
		pos = envData.Snr4_StartPos;
		len = envData.Snr4_Len;
	}
	memcpy(csn->num, a->uid + pos, len);
	csn->nlen = len;
#endif 
	memcpy(csn->num, a->uid, a->ulen);
	csn->nlen = a->ulen;
	csn->info = 0;
	csn->std = Card_T_CpuA;
	return ret;
}

static int Reader_MF_Service(ISO14443AInfo_T *a, CSN_T* csn){
	int ret = -1;
	//是否读取逻辑卡号
	if(Flag_IsSet(envData.rdSupport[1], ENV_Func_MF)){
		//读逻辑卡号
		ret = Reader_MF_GetLogicSN(a, csn);
	}
	else{
		//读取UID
		ret = Reader_MF_GetUID(a, csn);
	}
	return ret;
}

static int Reader_CPU_DoSelectAndAuthFile(uint16_t dfid, uint16_t efid, uint8_t kid, uint8_t key[], uint8_t klen){
	int ret;
	ret = Card_SelectFileById(Card_PICC, dfid);
	if(ret != 0){
		return ret;
	}
	
	ret = Card_SelectFileById(Card_PICC, efid);
	if(ret){
		return ret;
	}	
	ret = Reader_CPU_ExternAuth(kid, key, klen);
	if(ret){
		return -100;
	}
	return ret;
}

static inline int Reader_CPU_SelectAndAuthFile(void){
	uint16_t dfid = envData.rdCpuDfId;
	uint16_t efid = envData.rdCpuEfId;
	uint8_t kid = envData.rdCpuKeyId;
	uint8_t *key = envData.rdCpuKey;
	uint8_t klen = sizeof(envData.rdCpuKey);
	
	return Reader_CPU_DoSelectAndAuthFile(dfid, efid, kid, key, klen);
}


static int Reader_CPU_CheckCustomCode(void){
	//检查用户编码
	uint8_t code[4];
	int ret = Card_ReadBinary0(Card_PICC, envData.Customer_CPU_Position, code, sizeof(code));
	if(ret){
		return ret;
	}
	if(!Reader_CheckCustomerCode(code )){
		return -101;
	}
	return ret;
}

static int Reader_CPU_ReadInfo(CSN_T* csn){
	int ret;	
	//认证
	ret = Reader_CPU_SelectAndAuthFile();	
	if(ret){
		//认证失败，退出
		return ret;
	}
	//是否检查客户编码
	if(Flag_IsSet(envData.Options_select, ENV_Custom_CheckCode)){
		//检查用户编码
		ret = Reader_CPU_CheckCustomCode();
		if(ret){
			return ret;
		}
	}
	//读取卡号
	ret = Card_ReadBinary0(Card_PICC, envData.ContentStartPosition, csn->num, envData.ContentLength);
	if(ret){
		return ret;
	}
	csn->std = Card_T_CpuA;
	csn->info = 1;
	csn->nlen = envData.ContentLength;
	return ret;
}

static int Reader_CPU_GetLogicSN(ISO14443AInfo_T *a, CSN_T* csn){
	uint8_t ats[16];
	//激活CPU卡
	int ret = Port_Picc_Setup(Card_T_CpuA, a, ats);
	if(ret){
		return ret;
	}
	//读取CPU内容
	ret = Reader_CPU_ReadInfo(csn);	
	Port_Picc_Deactivate();
	Port_Picc_Destroy();
	return ret;
}

int Reader_CPU_CheckKey(ISO14443AInfo_T *a)
{
	uint8_t ats[16];
	int ret = Port_Picc_Setup(Card_T_CpuA, a, ats);
	if(ret){
		return ret;
	}
	
	ret = Reader_CPU_SelectAndAuthFile();	
	Port_Picc_Deactivate();
	Port_Picc_Destroy();
	return ret;
}


static int Reader_CPU_GetUID(ISO14443AInfo_T *a, CSN_T* csn){
	int ret = 0;
	
	if(Flag_IsSet(envData.Options_select, ENV_Custom_CPU_CheckKey)){
		ret = Reader_CPU_CheckKey(a);
		if(ret){
			return ret;
		}
	}
#if 0
	uint8_t pos;
	uint8_t len;
	
	if(a->ulen != 4){
		pos = envData.Snr8_StartPos;
		len = envData.Snr8_Len;
	}
	else{
		pos = envData.Snr4_StartPos;
		len = envData.Snr4_Len;
	}
	memcpy(csn->num, a->uid + pos, len);
#endif 
	memcpy(csn->num, a->uid, a->ulen);
	csn->nlen = a->ulen;
	csn->info = 0;
	csn->std = Card_T_CpuA;
	return ret;
}

static int Reader_CPU_Service(ISO14443AInfo_T *a, CSN_T* csn){
	int ret = -1;
	
	//是否读取逻辑卡号
	if(Flag_IsSet(envData.rdSupport[1], ENV_Func_CPU)){
		//读取逻辑卡号
		ret = Reader_CPU_GetLogicSN(a, csn);
	}
	else{
		//读取UID
		ret = Reader_CPU_GetUID(a, csn);
	}
	return ret;
}

int Reader_ReadTypeA(CSN_T* csn){
	ISO14443AInfo_T a;
	int ret = Reader_SearchTypeA(&a, 100);
	if(ret){
		return -200;
	}
	uint8_t sak = Reader_MultTypeSelect(a.sak);
	//判断是否是MF卡还是CPU卡
	if(CardType_IsCpu(sak)){
		//CPU卡		
		if(!Flag_IsSet(envData.rdSupport[0], ENV_Func_CPU)){
			return -1;
		}
		ret = Reader_CPU_Service(&a, csn);
	}
	else{
		//MF卡
		//MF是否使能
		if(!Flag_IsSet(envData.rdSupport[0], ENV_Func_MF)){
			return -1;
		}
		ret = Reader_MF_Service(&a, csn);
	}
	
	return ret;
}



static int Reader_CPU_ExternAuth(uint8_t kid, uint8_t key[], uint8_t klen){
	uint8_t rbuf[32];
	uint8_t cbuf[32];
	int ret;
	
	memset(rbuf, 0, sizeof(rbuf));
	memset(cbuf, 0, sizeof(cbuf));
	if((ret = Card_GetChallenge(Card_PICC, 0x08, cbuf)) != 0){
		DBG_WRITE("PICC GetChallenge Fail\r\n");
		return ret;
	}
	unsigned int clen;
	des_encrypt_data(cbuf, 8, rbuf, &clen, key, klen);
	if((ret = Card_RawExternalAuth(Card_PICC, kid, rbuf, 8)) != 0){
		DBG_WRITE("PICC ExternalAuth Fail\r\n");
		return ret;
	}
	return ret;
}
//WG码转换
uint8_t Reader_Config_GetWG(uint8_t WgCode)
{
	static const uint8_t wgTable[6] ={
		26, 34, 42, 50, 58, 66
	};

	if (WgCode < 6)	{
		return wgTable[WgCode];
	}
	return 34;
}

#define CFG_Move(dst, src)	memcpy(&(dst), &(src), sizeof(src))

static void Reader_ConfigSave(ConfigCardParam_T *config){
	//韦根配置
	envData.wg = Reader_Config_GetWG(config->Wg);
	CFG_Move(envData.wgParityFlag , config->WgParity);
	CFG_Move(envData.wgPulseWidth , config->WgPulse);
	CFG_Move(envData.wgReverse , config->WgReverse);
	
	CFG_Move(envData.rdCpuKey, config->CpuKey);	// //16字节 0 -15 
	CFG_Move(envData.rdCpuEfId, config->CpuEfId);	//1字节 16
	CFG_Move(envData.rdErrorWarnning, config->AlarmFlag) ;								//1字节 17
	CFG_Move(envData.rdMfKey, config->MfKey);								//6字节 [18]-[23]
	CFG_Move(envData.rdMfBlock, config->MfBlock);								//1字节 [24]
	CFG_Move(envData.rdMfOffset, config->MfOffset) ;								//1字节-[25]
	CFG_Move(envData.rdMode, config->Mode);									//1字节-[26]自定义卡选择
	CFG_Move(envData.rdCpuDfId, config->CpuDfId);								//2字节[32]-[33]
	CFG_Move(envData.rdSupport, config->rdSupport);						//2字节 [34]-[35] 自定义卡选择区
	
	CFG_Move(envData.rdInfoOpenDoor, config->InfoOpenDoor);							//??
	CFG_Move(envData.rdCpuKeyId, config->CpuKeyId);	
	CFG_Move(envData.rdMifareFirst, config->rdMifareFirst);		//CPU 卡和MF卡优先选择, 0 CPU卡优先；1 MF卡优先 ， 默认CPU卡优先 [40]

	CFG_Move(envData.ContentStartPosition, config->ContentStartPosition);					//Start position of read file that in cpu card.
	CFG_Move(envData.ContentLength, config->ContentLength);							//offset
	CFG_Move(envData.Customer_Code, config->Customer_Code);						//0: without customer code ;   !0: with customer code.
	CFG_Move(envData.Customer_M1_Position, config->Customer_M1_Position);
	CFG_Move(envData.Snr4_StartPos, config->Snr4_StartPos);
	CFG_Move(envData.Snr4_Len, config->Snr4_Len);
	CFG_Move(envData.Snr8_StartPos, config->Snr8_StartPos);
	CFG_Move(envData.Snr8_Len, config->Snr8_Len);
	CFG_Move(envData.Options_select, config->Options_select);

	Env_Update();
}

static int Reader_DoConfigService(void){
	//activate card
	int ret;	
	ISO14443AInfo_T a;
	
	ret = Port_Picc_Activate(Card_T_CpuA, PICC_Op_Activate, &a);
	if(ret){
		DBG_PRINT("Port_Picc_Activate fail:%d\r\n", ret);
		return ret;
	}
	
	uint8_t ats[16];
	if( (ret = Port_Picc_Setup(Card_T_CpuA, &a, ats)) != 0){
		DBG_PRINT("Port_Picc_Setup fail:%d\r\n", ret);
		return ret;
	}
	if((ret = Card_SelectFileById(Card_PICC, 0x0001)) != 0){
		DBG_WRITE("PICC Select DF01 Fail\r\n");
		return ret;
	}
	
	if((ret = Reader_CPU_ExternAuth(0x00, cfgKey, sizeof(cfgKey))) != 0){
		return -100;
	}
	ConfigCardParam_T e;
	if((ret = Card_ReadBinary0(Card_PICC, 0,(uint8_t*)&e, sizeof(e))) != 0){
		return ret;
	}
	Reader_ConfigSave(&e);
	return ret;
} 


int Reader_ConfigService(void){
	int ret;
	
	Port_Picc_SetRf(1);
	BSP_Sleep_Ms(10);		
	//activate card		
	ret = Reader_DoConfigService();
	Port_Picc_SetRf(0);
	return ret;
}



